|
1、基础知识
通过《USB HID 设备类协议入门》一文和上一节的实例我们知道决定HID设备“身份”的因素有
1)5个标准描述符中与HID设备有关的部分有:
- 设备描述符中bDeviceClass、bDeviceSubClass和bDeviceProtocol三个字段的值必须为零。
- 接口描述符中bInterfaceClass的值必须为0x03,bInterfaceSubClass的值为0或1,为1表示HID设备符是一个启动设备(Boot Device,一般对PC机而言才有意义,意思是BIOS启动时能识别并使用您的HID设备,且只有标准鼠标或键盘类设备才能成为Boot Device。 bInterfaceProtocol的取值含义如下表所示:
HID接口描述符中bInterfaceProtocol的含义 |
bInterfaceProtocol的取值(十进制) |
含义 |
0 |
NONE |
1 |
鼠标 |
2 |
键盘 |
3~255 |
保留 |
2)HID设备的描述符除了5个USB的标准描述符(设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符,见百合电子工作室的另一篇文章:USB开发基础--USB命令(请求)和USB描述符)外,还包括3个HID设备类特定描述符:HID描述符、报告描述符、实体描述符。
2、在上一节实例的基础上作一些修改来将Easy USB 51 Programer改造成键盘
1)下载上一节实例
2)修改接口描述符中bInterfaceProtocol的值为0x02
在Descriptor.c中找到以下代码
将其修改为
3)在上一节中也提到“虽然我们将接口描述符中的bInterfaceProtocol设为1(代表鼠标),但这只是针对启动设备(Boot Device)而言有才有效果(即PC机的BIOS加载后能识别和使用),但真正对HID设备的数据流格式进行描述的是报告描述符,所以 bInterfaceProtocol的取值实际意义不大”,所以现在我们来修改报告描述符
在Descriptor.c中找到以下代码:
- code char MouseReportDescriptor[52] = {
- 0x05, 0x01,
- 0x09, 0x02,
- 0xa1, 0x01,
- 0x09, 0x01,
- 0xa1, 0x00,
- 0x05, 0x09,
- 0x19, 0x01,
- 0x29, 0x03,
- 0x15, 0x00,
- 0x25, 0x01,
- 0x95, 0x03,
- 0x75, 0x01,
- 0x81, 0x02,
- 0x95, 0x01,
- 0x75, 0x05,
- 0x81, 0x03,
- 0x05, 0x01,
- 0x09, 0x30,
- 0x09, 0x31,
- 0x09, 0x38,
- 0x15, 0x81,
- 0x25, 0x7f,
- 0x75, 0x08,
- 0x95, 0x03,
- 0x81, 0x06,
- 0xc0,
- 0xc0
- };
将其修改为
- code char MouseReportDescriptor[63] = {
-
- 0x05, 0x01,
-
-
- 0x09, 0x06,
-
-
- 0xa1, 0x01,
-
-
- 0x05, 0x07,
-
-
- 0x19, 0xe0,
-
- 0x29, 0xe7,
-
- 0x15, 0x00,
-
- 0x25, 0x01,
-
- 0x75, 0x01,
-
- 0x95, 0x08,
-
-
- 0x81, 0x02,
-
-
-
-
-
-
-
-
-
- 0x95, 0x01,
-
- 0x75, 0x08,
-
- 0x81, 0x03,
-
-
-
-
-
- 0x95, 0x05,
-
- 0x75, 0x01,
-
- 0x05, 0x08,
-
- 0x19, 0x01,
-
- 0x29, 0x05,
-
-
- 0x91, 0x02,
-
-
- 0x95, 0x01,
-
- 0x75, 0x03,
-
- 0x91, 0x03,
-
-
-
-
- 0x95, 0x06,
-
- 0x75, 0x08,
-
- 0x15, 0x00,
-
- 0x25, 0xFF,
-
- 0x05, 0x07,
-
- 0x19, 0x00,
-
- 0x29, 0x65,
-
- 0x81, 0x00,
-
-
-
-
-
-
-
- 0xc0
- };
这们还需要将Descriptor.h中的以下代码
- extern code char MouseReportDescriptor[52];
修改为
- extern code char MouseReportDescriptor[63];
上面的报告描述符中只有一个报告,所以没有报告ID,
因此返回的都是实际使用的数据。总共有8字节输入,1字节输出。其中输入的
第一字节用来表示特殊按键,第二字节保留,后面的六字节为普通按键。如果
只有左ctrl键按下,则返回01 00 00 00 00 00 00 00(十六进制),如果
只有数字键1 按下,则返回00 00 59 00 00 00 00 00,如果数字
键1 和2 同时按下,则返回00 00 59 5A 00 00 00 00,如果
再按下左shift 键,则返回02 00 59 5A 00 00 00 00,
然后再释放1 键,则返回02 00 5A 00 00 00 00 00,
然后全部按键释放,则返回00 00 00 00 00 00 00 00。
这些数据(即报告)都是通过中断端点返回的。当按下Num Lock键时,PC会发送
输出报告,从报告描述符中我们知道,Num Lock的LED对应着输出报告的最低位,
当数字小键盘打开时,输出xxxxxxx1(二进制,打x的由其它的LED状态决定);
当数字小键盘关闭时,输出xxxxxxx0(同前)。取出最低位就可以控制数字键锁定LED了。
(注:以上说明摘自computer00的《USB HID报告及报告描述符简介》一文)
5)将Descriptor中如下语句
修改为
4)模拟NumLock键盘和Windows键
我们定义扩展板EXT-BOARD-A上的K1键对应Windows键(即USB HID Usage Table中定义的GUI键,Left GUI或Right GUI,我们这里就选Left GUI吧),而K2键盘对应NumLock键,当NumLock使能时应点亮NumLock指示灯,我定义D0为NumLock指示灯。
根据报告描述符的定义,再参考USB HID Usage Table,要模拟Windows键盘,应将送给主机的8个字节的第一个字节置为0x04,要模拟NumLock键,应将第三个字节置为0x53。如果要模拟NumLock指示灯,不应该在主控芯片里判断当到K2按下后就打开或熄灭LED,其正确的方法是:当主机接收到NumLock按键信息后,会根据系统当前NumLock的状态决定打开还是关闭LED指示灯,然后将这一信息通过传给设备(发送一个字节的数据给设置,最低位表示NumLock的状态)。
更改Main.c文件中的main函数为:
在测试这个例子时,按下EXT-BOARD-A上的K1键,会弹出开始菜单,按K2键,D0的状态会改变,同时原有键盘上的NumLock指示灯也会同EXT-BOARD-A上的D0状态同步,相反,按原有键盘上的NumLock键,D0的状态也会跟着改变。
下载源代码
|
|